#ifndef _WX_GENERIC_CALCTRL_H
#define _WX_GENERIC_CALCTRL_H

#include "wx/control.h"         // the base class
#include "wx/dcclient.h"        // for wxPaintDC

class wxComboBox;
class wxStaticText;
class wxSpinCtrl;

#define wxCalendarNameStr wxT("CalendarCtrl")

class wxCalendarCtrl : public wxControl {
  public:
    // construction
    wxCalendarCtrl() { Init(); }
    wxCalendarCtrl( wxWindow *parent, wxWindowID id, const wxDateTime& date = wxDefaultDateTime,
                    const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
                    long style = wxCAL_SHOW_HOLIDAYS | wxWANTS_CHARS, const wxString& name = wxCalendarNameStr );

    bool Create( wxWindow *parent, wxWindowID id, const wxDateTime& date = wxDefaultDateTime,
                 const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
                 long style = wxCAL_SHOW_HOLIDAYS | wxWANTS_CHARS, const wxString& name = wxCalendarNameStr );

    virtual ~wxCalendarCtrl();
    virtual bool Destroy();
    bool SetDate( const wxDateTime& date ); // we need to be able to control if the event should be sent in SetDateAndNotify(...)
    const wxDateTime& GetDate() const { return m_date; }
    bool SetLowerDateLimit( const wxDateTime& date = wxDefaultDateTime );
    const wxDateTime& GetLowerDateLimit() const { return m_lowdate; }
    bool SetUpperDateLimit( const wxDateTime& date = wxDefaultDateTime );
    const wxDateTime& GetUpperDateLimit() const { return m_highdate; }
    bool SetDateRange( const wxDateTime& lowerdate = wxDefaultDateTime, const wxDateTime& upperdate = wxDefaultDateTime );
    void EnableYearChange( bool enable = true );
    void EnableMonthChange( bool enable = true );
    void EnableHolidayDisplay( bool display = true );
    void SetHeaderColours( const wxColour& colFg, const wxColour& colBg ) {
      m_colHeaderFg = colFg;
      m_colHeaderBg = colBg;
    }
    const wxColour& GetHeaderColourFg() const { return m_colHeaderFg; }
    const wxColour& GetHeaderColourBg() const { return m_colHeaderBg; }
    void SetHighlightColours( const wxColour& colFg, const wxColour& colBg ) {
      m_colHighlightFg = colFg;
      m_colHighlightBg = colBg;
    }
    const wxColour& GetHighlightColourFg() const { return m_colHighlightFg; }
    const wxColour& GetHighlightColourBg() const { return m_colHighlightBg; }
    void SetHolidayColours( const wxColour& colFg, const wxColour& colBg ) {
      m_colHolidayFg = colFg;
      m_colHolidayBg = colBg;
    }

    const wxColour& GetHolidayColourFg() const { return m_colHolidayFg; }
    const wxColour& GetHolidayColourBg() const { return m_colHolidayBg; }
    wxCalendarDateAttr *GetAttr( size_t day ) const {
      wxCHECK_MSG( day > 0 && day < 32, NULL, wxT( "invalid day" ) );
      return m_attrs[day - 1];
    }

    void SetAttr( size_t day, wxCalendarDateAttr *attr ) {
      wxCHECK_RET( day > 0 && day < 32, wxT( "invalid day" ) );
      delete m_attrs[day - 1];
      m_attrs[day - 1] = attr;
    }

    void SetHoliday( size_t day );

    void ResetAttr( size_t day ) { SetAttr( day, ( wxCalendarDateAttr * )NULL ); }
    wxCalendarHitTestResult HitTest( const wxPoint& pos, wxDateTime *date = NULL, wxDateTime::WeekDay *wd = NULL );
    virtual bool Enable( bool enable = true );
    virtual bool Show( bool show = true );
    virtual void SetWindowStyleFlag( long style );
    virtual wxVisualAttributes GetDefaultAttributes() const { return GetClassDefaultAttributes( GetWindowVariant() ); }
    static wxVisualAttributes
    GetClassDefaultAttributes( wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL );
    void OnSysColourChanged( wxSysColourChangedEvent& event );
  protected:
    virtual wxSize DoGetBestSize() const;
    virtual void DoGetPosition( int *x, int *y ) const;
    virtual void DoGetSize( int *width, int *height ) const;
    virtual void DoSetSize( int x, int y, int width, int height, int sizeFlags );
    virtual void DoMoveWindow( int x, int y, int width, int height );

  private:
    void Init();
    void InitColours();
    void OnPaint( wxPaintEvent& event );
    void OnClick( wxMouseEvent& event );
    void OnDClick( wxMouseEvent& event );
    void OnChar( wxKeyEvent& event );
    void OnMonthChange( wxCommandEvent& event );
    void OnYearChange( wxCommandEvent& event );
    void OnYearTextChange( wxCommandEvent& event );
    void RecalcGeometry();
    void SetDateAndNotify( const wxDateTime& date );
    size_t GetWeek( const wxDateTime& date ) const;
    wxDateTime GetStartDate() const;
    bool IsDateShown( const wxDateTime& date ) const;
    bool IsDateInRange( const wxDateTime& date ) const;
    bool ChangeYear( wxDateTime* target ) const;
    bool ChangeMonth( wxDateTime* target ) const;
    void RefreshDate( const wxDateTime& date );
    void ChangeDay( const wxDateTime& date );
    void SetHolidayAttrs();
    void ResetHolidayAttrs();
    void GenerateEvent( wxEventType type ) {
      wxCalendarEvent event( this, type );
      ( void )GetEventHandler()->ProcessEvent( event );
    }

    void GenerateEvents( wxEventType type1, wxEventType type2 ) {
      GenerateEvent( type1 );
      GenerateEvent( type2 );
    }
    bool AllowMonthChange() const {
      return ( GetWindowStyle() & wxCAL_NO_MONTH_CHANGE )
             != wxCAL_NO_MONTH_CHANGE;
    }
    bool AllowYearChange() const {
      return !( GetWindowStyle() & wxCAL_NO_YEAR_CHANGE );
    }
    void ShowCurrentControls();
    void CreateMonthComboBox();
    void CreateYearSpinCtrl();
  public:
    wxControl *GetMonthControl() const;
    wxControl *GetYearControl() const;

  private:
    void HighlightRange( wxPaintDC* dc, const wxDateTime& fromdate, const wxDateTime& todate, const wxPen* pen, const wxBrush* brush );
    bool GetDateCoord( const wxDateTime& date, int *day, int *week ) const;
    void SetUserChangedYear() { m_userChangedYear = true; }
    wxStaticText *m_staticMonth;
    wxComboBox *m_comboMonth;
    wxStaticText *m_staticYear;
    wxSpinCtrl *m_spinYear;
    wxDateTime m_date;
    wxDateTime m_lowdate;
    wxDateTime m_highdate;
    wxColour m_colHighlightFg,
             m_colHighlightBg,
             m_colHolidayFg,
             m_colHolidayBg,
             m_colHeaderFg,
             m_colHeaderBg,
             m_colBackground,
             m_colSorrounding;
    wxCalendarDateAttr *m_attrs[31];
    wxCoord m_widthCol,
            m_heightRow,
            m_rowOffset;

    wxRect m_leftArrowRect,
           m_rightArrowRect;
    wxString m_weekdays[7];
    bool m_userChangedYear;
    DECLARE_DYNAMIC_CLASS( wxCalendarCtrl )
    DECLARE_EVENT_TABLE()
    DECLARE_NO_COPY_CLASS( wxCalendarCtrl )
};

#endif
